/*
 * Semaforo.cpp
 *
 *  Created on: 02/04/2014
 *      Author: migue
 */

#include "Semaforo.h"

#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#include <string.h>
#include <errno.h>

#include <stdio.h>

#include <syslog.h>

union semnum {
	int val;
	struct semid_ds* buf;
	ushort* array;
};

Semaforo::Semaforo(const char* ruta ,int cant, char id, bool crear) {

	if (cant <= 0) {
		syslog(LOG_INFO, "Cantidad de Semaforos negativa, ruta: %s, cant: %i id: %i, crear: %i", ruta, cant, id, crear);
		perror("Cantidad de Semaforos negativa");
		exit(EXIT_FAILURE);
	}

	_cant = cant;

	key_t clave = ftok(ruta, id);

	if (clave == -1) {
		syslog(LOG_INFO, "Error al obtener ftok() de archivo de Semaforos, ruta: %s, cant: %i id: %i, crear: %i", ruta, cant, id, crear);
		perror("Error al obtener ftok() de archivo de Semaforos");
		exit(EXIT_FAILURE);
	}


	if (crear) {
		_semId = semget(clave, _cant, IPC_CREAT | IPC_EXCL | 0660);

		if (_semId == -1) {
			syslog(LOG_INFO, "Error al CREAR Semaforo, ruta: %s, cant: %i id: %i, crear: %i", ruta, cant, id, crear);
			perror("Error al CREAR Semaforo");
			exit(EXIT_FAILURE);
		}

	}
	else {
		_semId = semget(clave, _cant, 0660);

		if (_semId == -1) {
			syslog(LOG_INFO, "Error al intentar obtener identificador de Semaforos, ruta: %s, cant: %i id: %i, crear: %i", ruta, cant, id, crear);
			perror("Error al intentar obtener identificador de Semaforos");
			exit(EXIT_FAILURE);
		}
	}
}


Semaforo::~Semaforo() {
}


void Semaforo::inicializar(int val) {
	semnum valor;
	valor.val = val;

	for (int i = 0; i < _cant ; i++) {
		if (semctl(_semId, i, SETVAL, valor ) == -1) {
			syslog(LOG_INFO, "error al inicializar semaforos, _semId: %i, valor.val: %i", _semId, valor.val);
			perror("error al inicializar semaforos");
			exit(EXIT_FAILURE);
		}
	}
}

void Semaforo::wait(int numSem) {
	if ( numSem < _cant && numSem >= 0 ) {
		struct sembuf op;
		op.sem_num = numSem;
		op.sem_flg = 0;
		op.sem_op = -1;

		if (semop( _semId, &op, 1) == -1 ) {
			syslog(LOG_INFO, "Error al intentar operacion wait() en semaforo, _semId: %i, numSem: %i", _semId, numSem);
			perror("Error al intentar operacion wait() en semaforo");
			exit(EXIT_FAILURE);
		}

	}
	else {
		syslog(LOG_INFO, "Error numero de semaforo en wait(), _semId: %i, numSem: %i", _semId, numSem);
		perror("Error numero de semaforo en wait");
		exit(EXIT_FAILURE);
	}
}

void Semaforo::signal(int numSem) {
	if ( numSem < _cant && numSem >= 0 ) {
		struct sembuf op;
		op.sem_num = numSem;
		op.sem_flg = 0;
		op.sem_op = 1;

		if (semop( _semId, &op, 1) == -1 ) {
			syslog(LOG_INFO, "Error al intentar operacion signal() en semaforo, _semId: %i, numSem: %i", _semId, numSem);
			perror("Error al intentar operacion signal() en semaforo");
			exit(EXIT_FAILURE);
		}

	}
	else {
		syslog(LOG_INFO, "Error numero de semaforo en signal(), _semId: %i, numSem: %i", _semId, numSem);
		perror("Error numero de semaforo en signal");
		exit(EXIT_FAILURE);
	}
}

void Semaforo::destruir() {
	if (semctl( _semId, 0 , IPC_RMID) == -1) {
		syslog(LOG_INFO, "Error al intentar destruir semaforo, _semId: %i", _semId);
		perror("Error al intentar destruir semaforo");
	}
}

void Semaforo::destruirSemaforo(const char* ruta, int cant, char id) {

	if (cant <= 0) {
		perror("Cantidad de Semaforos negativa");
		return;
	}


	key_t clave = ftok(ruta, id);

	if (clave == -1) {
		perror("Error al obtener ftok() de archivo de Semaforos");
		return;
	}

	int semId = semget(clave, cant, 0660);

	if (semId == -1) {
		perror("Error al intentar obtener identificador de Semaforos");
		return;
	}

	if (semctl( semId, 0 , IPC_RMID) == -1) {
		syslog(LOG_INFO, "Error al intentar destruir semaforo, _semId: %i", semId);
		perror("Error al intentar destruir semaforo");
	}
}
